﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Terminal.Advanced_AEUC_settings_controls.Settings_AUX;
using Terminal.Advanced_AEUC_settings_controls.Settings_Interfaces;
using Auxiliaries;

namespace Terminal.Advanced_AEUC_settings_controls.Scripting
{
    /// <summary>
    /// Parsing of a text script
    /// </summary>
    static class ScrCmdParser
    {
        /// <summary>
        /// Parses a command line and attempts to execute it
        /// </summary>
        /// <param name="cmdLine">The command line to be parsed and executed</param>
        /// /// <param name="linePos">A reference to the current char index in the cmdLine string</param>
        /// <param name="scrComponents">All of the possible script components that are currently supported</param>
        /// <returns>True if successful</returns>
        static public bool ExecCmdLine(string cmdLine, ref int linePos, ScrMainModule.ScrComp scrComponents)
        {
            string scrWord;
            ScrBasicAction selAction;
            GenPayloadStruct pldAccess;
            bool opSuccessfull = true;

            scrWord = ReadWord(ref linePos, cmdLine);
            selAction = ResolveScriptAction(scrWord, scrComponents.scrActions);

            if (selAction != null)
            {
                opSuccessfull = selAction.Do(ResolveActionParamList(selAction.GetParamList(), ref linePos, cmdLine, scrComponents));
            }
            else
            {
                pldAccess = ResolveScriptPayloadStruct("RTE", scrWord, scrComponents);
                if (pldAccess == null)
                {
                    string compName = scrWord;
                    scrWord = ReadWord(ref linePos, cmdLine);
                    pldAccess = ResolveScriptPayloadStruct(compName, scrWord, scrComponents);

                    if (pldAccess == null)
                    {
                        //Restore parsing
                        linePos -= scrWord.Length;
                        scrWord = compName;
                    }
                }

                if (pldAccess != null)
                {
                    if (ReadWord(ref linePos, cmdLine) == ".")
                    {
                        string assignId = ReadWord(ref linePos, cmdLine);

                        try
                        {
                            ulong tmp = pldAccess[assignId];
                        }
                        catch (Exception ex)
                        {
                            if (pldAccess.Editable)
                            {
                                bool ptr = false;
                                uint vrSz = 4;
                                char pk;
                                PeekChar(linePos, cmdLine, out pk);
                                if (pk != '=')
                                {
                                    scrWord = ReadWord(ref linePos, cmdLine);
                                    if (scrWord == "ptr")
                                    {
                                        ptr = true;
                                        vrSz = 4;
                                    }
                                    else if (!uint.TryParse(scrWord, out vrSz))
                                    {
                                        vrSz = 4;
                                    }
                                }
                                uint newID = 0;
                                GenAEUCSetting[] prsntItems = pldAccess.StructContents;
                                if (prsntItems.Length > 0)
                                    newID = prsntItems[prsntItems.Length - 1].AEUC_id + 1;

                                IAEUCSetting[] runTVar = new IAEUCSetting[1];
                                runTVar[0] = new GenPayloadStruct.NewPldItem();
                                runTVar[0].AEUC_DisplayName = assignId;
                                runTVar[0].AEUC_Id = newID;
                                runTVar[0].AEUC_Size = vrSz;
                                runTVar[0].AEUC_RefPointer = ptr;

                                pldAccess.SetPayloadItems(runTVar);

                                scrComponents.rteCmn.updateComp(null);
                            }
                            else
                                throw ex;
                        }

                        scrWord = ReadWord(ref linePos, cmdLine);
                        switch (scrWord)
                        {
                            case "=":
                                {
                                    char peek;
                                    PeekChar(linePos, cmdLine, out peek);
                                    if (peek == '\"')
                                    {
                                        pldAccess.setStringItem(pldAccess[assignId], ReadString(ref linePos, cmdLine));
                                    }
                                    else
                                    {
                                        if (peek != '%')
                                        {
                                            //If an arythmetic expression or single integer (structure dereference) is to be done, a calculation
                                            //will be run as the ParseInfixArithmeticExpression would do all the work and the Calculate will return 
                                            //a correct value even if the expression is single symbol only.
                                            pldAccess[pldAccess[assignId]] = Calculator.Calculate(ParseInfixArithmeticExpression(ref linePos, cmdLine, scrComponents));
                                        }
                                        else
                                        {
                                            scrWord = ReadWord(ref linePos, cmdLine);
                                            scrWord = scrWord.Remove(0, 1);//Remove the '%'
                                            GenPayloadStruct rdTmpPld = ResolveScriptPayloadStruct("RTE", scrWord, scrComponents);
                                            if (rdTmpPld == null)
                                            {
                                                string rdTmpCompName = scrWord;
                                                scrWord = ReadWord(ref linePos, cmdLine);
                                                rdTmpPld = ResolveScriptPayloadStruct(rdTmpCompName, scrWord, scrComponents);

                                                if (rdTmpPld == null)
                                                {
                                                    throw new Exception("Unrecognized operation!");
                                                }
                                            }
                                            
                                            if (ReadWord(ref linePos, cmdLine) != ".")
                                                throw new Exception("Missing structuter accessor.");
                                            
                                            scrWord = ReadWord(ref linePos, cmdLine);
                                            //If the parsed string was not an arithmetic expression, assume its structure string field and try again dereferencing it.
                                            pldAccess.setStringItem(pldAccess[assignId], rdTmpPld.getParamStringVal(rdTmpPld[scrWord]));
                                        }
                                    }
                                }
                                break;
                            default:
                                throw new Exception("Unrecognized operation!");
                        }
                    }
                    else
                        throw new Exception("Missing structuter accessor.");
                }
                else if (scrWord != "" && scrWord != ";" && !(scrWord.Length > 0 && scrWord[scrWord.Length - 1] == ':'))
                    throw new Exception("Undefined token " + scrWord);
            }

            while (linePos < cmdLine.Length && scrWord != ";")
                scrWord = ReadWord(ref linePos, cmdLine);

            return opSuccessfull;
        }
        /// <summary>
        /// Parses a command line and generates C source code
        /// </summary>
        /// <param name="cmdLine">The command line to be parsed and executed</param>
        /// /// <param name="linePos">A reference to the current char index in the cmdLine string</param>
        /// <param name="scrComponents">All of the possible script components that are currently supported</param>
        /// <returns>True if successful</returns>
        static public string SourcesifyCmdLine(string cmdLine, ref int linePos, ScrMainModule.ScrComp scrComponents)
        {
            string scrWord;
            ScrBasicAction selAction;
            GenPayloadStruct pldAccess;

            string c_source = "";

            scrWord = ReadWord(ref linePos, cmdLine);
            selAction = ResolveScriptAction(scrWord, scrComponents.scrActions);

            if (selAction != null)
            {
                c_source = selAction.GenerateSourceCode(ResolveActionParamList(selAction.GetParamList(), ref linePos, cmdLine, scrComponents));
            }
            else
            {
                pldAccess = ResolveScriptPayloadStruct("RTE", scrWord, scrComponents);
                if (pldAccess == null)
                {
                    string compName = scrWord;
                    scrWord = ReadWord(ref linePos, cmdLine);
                    pldAccess = ResolveScriptPayloadStruct(compName, scrWord, scrComponents);

                    if (pldAccess == null)
                    {
                        //Restore parsing
                        linePos -= scrWord.Length;
                        scrWord = compName;
                    }
                }

                if (pldAccess != null)
                {
                    c_source = "\t" + pldAccess.dispName;

                    if (ReadWord(ref linePos, cmdLine) == ".")
                    {
                        c_source += ".";

                        string assignId = ReadWord(ref linePos, cmdLine);

                        try
                        {
                            ulong tmp = pldAccess[assignId];
                        }
                        catch (Exception ex)
                        {
                            if (pldAccess.Editable)
                            {
                                uint newID = 0;
                                GenAEUCSetting[] prsntItems = pldAccess.StructContents;
                                if (prsntItems.Length > 0)
                                    newID = prsntItems[prsntItems.Length - 1].AEUC_id + 1;

                                IAEUCSetting[] runTVar = new IAEUCSetting[1];
                                runTVar[0] = new GenPayloadStruct.NewPldItem();
                                runTVar[0].AEUC_DisplayName = assignId;
                                runTVar[0].AEUC_Id = newID;

                                pldAccess.SetPayloadItems(runTVar);

                                scrComponents.rteCmn.updateComp(null);
                            }
                            else
                                throw ex;
                        }

                        c_source += assignId;

                        scrWord = ReadWord(ref linePos, cmdLine);
                        switch (scrWord)
                        {
                            case "=":
                                {
                                    char peek;
                                    PeekChar(linePos, cmdLine, out peek);
                                    if (peek == '\"')
                                    {
                                        //c_source += " = ";
                                        //TODO: need a workaround - should be declared as poitner in the struct to be
                                        //able to work with various size strings...
                                        pldAccess.setStringItem(pldAccess[assignId], ReadString(ref linePos, cmdLine));
                                        //c_source += "\"" + ReadString(ref linePos, cmdLine) + "\"";
                                    }
                                    else
                                    {
                                        c_source += " = ";
                                        scrWord = ReadString(ref linePos, cmdLine);
                                        while (scrWord != ";" && linePos < cmdLine.Length)
                                        {
                                            c_source += scrWord;
                                            scrWord = ReadWord(ref linePos, cmdLine);
                                        }
                                    }
                                }
                                break;
                            default:
                                throw new Exception("Unrecognized operation!");
                        }

                        c_source += ";";
                    }
                    else
                        throw new Exception("Missing structuter accessor.");
                }
                else if (scrWord != "" && scrWord != ";" && !(scrWord.Length > 0 && scrWord[scrWord.Length - 1] == ':'))
                    throw new Exception("Undefined token " + scrWord);
                else
                    c_source += scrWord;
            }

            while (linePos < cmdLine.Length && scrWord != ";")
                scrWord = ReadWord(ref linePos, cmdLine);

            c_source += "\n";

            return c_source;
        }
        /// <summary>
        /// Generates typedefines based on the available script OMX components and RTE structures
        /// </summary>
        /// <param name="scrComponents">Available script components</param>
        /// <returns></returns>
        static public string SourcesifyFinalizaiton(ref string pre_proc_source, string scriptName, ScrMainModule.ScrComp scrComponents)
        {
            string typedefSection = "";
            string defSection = "";
            string initSection = "static void scrMod_" + scriptName + "_initDefinedStructs()\n{\n";

            for (int i = 0; i < scrComponents.compHdls.Length; i++)
            {
                for (int k = 0; k < scrComponents.compHdls[i].scrPldStructs.Length; k++)
                {
                    while (pre_proc_source.Contains(scrComponents.compHdls[i].scrPldStructs[k].dispName + "_t " + scrComponents.compHdls[i].scrPldStructs[k].dispName + ";\n"))
                    {
                        typedefSection += "typedef struct\n";
                        typedefSection += "{\n";
                        for (int t = 0; t < scrComponents.compHdls[i].scrPldStructs[k].StructContentsForcedOffset.Length; t++)
                        {
                            int sz = (int)scrComponents.compHdls[i].scrPldStructs[k].StructContentsForcedOffset[t].AEUC_size;
                            string dispName = scrComponents.compHdls[i].scrPldStructs[k].structContentsStringRep[t].dispName;

                            if (sz == 1)
                            {
                                typedefSection += "\tTIMM_OSAL_U8 " + dispName + ";\n";
                            }
                            else if (sz == 2)
                            {
                                typedefSection += "\tTIMM_OSAL_U16 " + dispName + ";\n";
                            }
                            else if (sz == 4)
                            {
                                typedefSection += "\tTIMM_OSAL_U32 " + dispName + ";\n";
                            }
                            else
                            {
                                typedefSection += "\tTIMM_OSAL_U8 " + dispName + "[" + sz.ToString() + "];\n";
                            }

                            if (sz == 1 || sz == 2 || sz == 4)
                            {
                                Int64 accval = 0;
                                for (int szI = 0; szI < sz; szI++)
                                {
                                    accval |= ((Int64)scrComponents.compHdls[i].scrPldStructs[k].StructContentsForcedOffset[t].AEUC_val[szI] << (8 * szI));
                                }
                                initSection += "\t" + scrComponents.compHdls[i].scrPldStructs[k].dispName + "." + dispName + " = " + accval.ToString() + ";\n";
                            }
                            else
                            {
                                for (int szI = 0; szI < sz; szI++)
                                {
                                    initSection += "\t" + scrComponents.compHdls[i].scrPldStructs[k].dispName + "." + dispName + "[" + szI.ToString() + "] = " +
                                                            scrComponents.compHdls[i].scrPldStructs[k].StructContentsForcedOffset[t].AEUC_val[szI].ToString() + ";\n";
                                }
                            }
                        }
                        typedefSection += "} " + scrComponents.compHdls[i].scrPldStructs[k].dispName + "_t" + ";\n\n";
                        initSection += "\n";
                        
                        defSection += scrComponents.compHdls[i].scrPldStructs[k].dispName + "_t " + scrComponents.compHdls[i].scrPldStructs[k].dispName + ";\n";

                        pre_proc_source = pre_proc_source.Replace(scrComponents.compHdls[i].scrPldStructs[k].dispName + "_t " + scrComponents.compHdls[i].scrPldStructs[k].dispName + ";\n", "");
                    }

                    while (pre_proc_source.Contains("_t " + scrComponents.compHdls[i].scrPldStructs[k].dispName + ";\n"))
                    {
                        int srchIndx = pre_proc_source.IndexOf("_t " + scrComponents.compHdls[i].scrPldStructs[k].dispName + ";\n") - 1;
                        string type = "";
                        while (srchIndx >= 0 && pre_proc_source[srchIndx] != ' ' && pre_proc_source[srchIndx] != ';' && pre_proc_source[srchIndx] != '\n' && pre_proc_source[srchIndx] != '\t')
                        {
                            type = pre_proc_source[srchIndx] + type;
                            srchIndx--;
                        }
                        
                        defSection += type + "_t " + scrComponents.compHdls[i].scrPldStructs[k].dispName + ";\n";

                        pre_proc_source = pre_proc_source.Replace(type + "_t " + scrComponents.compHdls[i].scrPldStructs[k].dispName + ";\n", "");

                        if (!typedefSection.Contains("} " + type + "_t" + ";\n\n"))
                        {
                            int j = 0;
                            int l = 0;
                            bool stop = false;
                            for (l = 0; l < scrComponents.compHdls.Length; l++)
                            {
                                for (j = 0; j < scrComponents.compHdls[l].scrPldStructs.Length; j++)
                                {
                                    if (scrComponents.compHdls[l].scrPldStructs[j].dispName == type)
                                    {
                                        stop = true;
                                        break;
                                    }
                                }
                                if (stop)
                                    break;
                            }

                            typedefSection += "typedef struct\n";
                            typedefSection += "{\n";
                            for (int t = 0; t < scrComponents.compHdls[l].scrPldStructs[j].StructContentsForcedOffset.Length; t++)
                            {
                                int sz = (int)scrComponents.compHdls[l].scrPldStructs[j].StructContentsForcedOffset[t].AEUC_size;
                                string dispName = scrComponents.compHdls[l].scrPldStructs[j].structContentsStringRep[t].dispName;
                                if (sz == 1)
                                {
                                    typedefSection += "\tTIMM_OSAL_U8 " + dispName + ";\n";
                                }
                                else if (sz == 2)
                                {
                                    typedefSection += "\tTIMM_OSAL_U16 " + dispName + ";\n";
                                }
                                else if (sz == 4)
                                {
                                    typedefSection += "\tTIMM_OSAL_U32 " + dispName + ";\n";
                                }
                                else
                                {
                                    typedefSection += "\tTIMM_OSAL_U8 " + dispName + "[" + sz.ToString() + "];\n";
                                }

                                if (sz == 1 || sz == 2 || sz == 4)
                                {
                                    Int64 accval = 0;
                                    for (int szI = 0; szI < sz; szI++)
                                    {
                                        accval |= ((Int64)scrComponents.compHdls[l].scrPldStructs[j].StructContentsForcedOffset[t].AEUC_val[szI] << (8 * szI));
                                    }
                                    initSection += "\t" + scrComponents.compHdls[l].scrPldStructs[j].dispName + "." + dispName + " = " + accval.ToString() + ";\n";
                                }
                                else
                                {
                                    for (int szI = 0; szI < sz; szI++)
                                    {
                                        initSection += "\t" + scrComponents.compHdls[l].scrPldStructs[j].dispName + "." + dispName + "[" + szI.ToString() + "] = " +
                                                                scrComponents.compHdls[l].scrPldStructs[j].StructContentsForcedOffset[t].AEUC_val[szI].ToString() + ";\n";
                                    }
                                }
                            }
                            typedefSection += "} " + scrComponents.compHdls[l].scrPldStructs[j].dispName + "_t" + ";\n\n";
                            initSection += "\n";

                            defSection += scrComponents.compHdls[l].scrPldStructs[j].dispName + "_t " + scrComponents.compHdls[l].scrPldStructs[j].dispName + ";\n";
                        }
                    }
                }
            }

            defSection += "\n";

            initSection += "}\n";
            initSection += "\nstatic void scrMod_" + scriptName + "_exec()\n{\n";
            initSection += "\tscrMod_" + scriptName + "_initDefinedStructs();\n";

            return typedefSection + defSection + initSection;
        }
        /// <summary>
        /// Searches the command line for any of the supplied search strings and returns true if any are found
        /// </summary>
        /// <param name="cmdLine">Command line to search through</param>
        /// <param name="linePos">Reference of the current position within the command line</param>
        /// <param name="searchee">Array of search string items</param>
        /// <param name="srchHit">Out parameter of the idnex of the found item</param>
        /// <returns>Search success status</returns>
        static public bool SearchCmdLine(string cmdLine, ref int linePos, string[] searchee, out int srchHit)
        {
            string scrWord;
            srchHit = -1;

            while (linePos < cmdLine.Length)
            {
                scrWord = ReadWord(ref linePos, cmdLine);
                for (int i = 0; i < searchee.Length; i++)
                {
                    if (scrWord == searchee[i])
                    {
                        srchHit = i;
                        return true;
                    }
                }
            }

            return false;
        }
        /// <summary>
        /// Checks if there is any valid symbol/word on the command line that can be executed.
        /// </summary>
        /// <param name="cmdLine">Command line to check</param>
        /// <returns>Boolean result</returns>
        static public bool ExecLineValidity(string cmdLine)
        {
            if (cmdLine.Length == 0)
                return false;
            
            int idx = 0;
            if (ReadWord(ref idx, cmdLine) == "")
                return false;

            return true;
        }

        #region Reading words, special expressions definitions and parisng functions
        /// <summary>
        /// Checks if a character is an arithmetic expression entry point symbol
        /// </summary>
        /// <param name="ch">Character to test</param>
        /// <returns>Bool result</returns>
        static bool CharIsArithmeticEntry(char ch)
        {
            if (ch == '}' ||
                ch == '{')
                return true;
            else
                return false;
        }
        /// <summary>
        /// Checks if a character is an arithmetic symbol (of interest)
        /// </summary>
        /// <param name="str">Character to test</param>
        /// <returns>Bool result</returns>
        static bool StringIsArithmeticSym(string str)
        {
            if (CharIsArithmeticEntry(str[0]) || Calculator.StringIsArithmeticOperation(str))
                return true;
            else
                return false;
        }
        /// <summary>
        /// Checks if a character is a struct or system accessor
        /// </summary>
        /// <param name="ch">Character to test</param>
        /// <returns>Bool result</returns>
        static bool CharIsAccessor(char ch)
        {
            if (ch == '.' || ch == ';')
                return true;
            else
                return false;
        }
        /// <summary>
        /// Reads a complete word from a string - word defined by two spaces
        /// </summary>
        /// <param name="index_pos">The position within the string where to start the reading</param>
        /// <param name="line">The string which is to be read</param>
        /// <returns>The word extratced from the string</returns>
        static public string ReadWord(ref int index_pos, string line)
        {
            //Flag indicating if parsed word is commented
            bool commentedLine = false;//C++ type of comment "//"
            bool commentedSection = false;//Block type comment "/* ... */"
            //The parsed word result
            String word = "";

            if (index_pos > -1 && line.Length > 0)
            {
                while (index_pos < line.Length && (Calculator.CharIsWordSeparator(line[index_pos])))
                    index_pos++;

                while (index_pos < line.Length && 
                        (
                            CharIsAccessor(line[index_pos]) || 
                            (
                                StringIsArithmeticSym(line.Substring(index_pos,1)) ||
                                (index_pos < line.Length - 1 && StringIsArithmeticSym(line.Substring(index_pos, 2)))
                            )
                                                
                        )
                    )
                {
                    if (line[index_pos] == '/')
                    {
                        if (index_pos + 1 < line.Length && line[index_pos + 1] == '/')
                            commentedLine = true;
                        else if (index_pos + 1 < line.Length && line[index_pos + 1] == '*')
                            commentedSection = true;
                    }

                    if (!(commentedLine || commentedSection))
                    {
                        //Special case handling - as the whole function is working
                        //on single character basis and there are three two character
                        // arithmetic operations, hence this if....
                        if (index_pos < line.Length - 1 && StringIsArithmeticSym(line.Substring(index_pos + 1, 1)) && StringIsArithmeticSym(line.Substring(index_pos, 2)))
                        {
                            index_pos += 2;
                            return line.Substring(index_pos - 2, 2);
                        }
                        else
                        {
                            index_pos++;
                            return "" + line[index_pos - 1];
                        }
                    }
                    else
                    {
                        if (commentedLine)
                        {
                            index_pos = line.Length;
                            return line.Substring(index_pos);
                        }
                        else if (commentedSection)
                        {
                            //Jump over the start of the comment - "/*"
                            index_pos += 2;

                            while (index_pos < line.Length - 1 && !(line[index_pos] == '*' && line[index_pos + 1] == '/'))
                                index_pos++;

                            //Check if line end was not the case to stop the traversal - if it is not, end of the comment should be found - "*/"
                            if (index_pos < line.Length - 1 && line[index_pos] == '*' && line[index_pos + 1] == '/')
                                index_pos += 2;//Jump over the end of the comment - "*/"

                            commentedSection = false;
                        }
                    }
                }
                while (index_pos < line.Length && !Calculator.CharIsWordSeparator(line[index_pos]) && !CharIsAccessor(line[index_pos]) && !(StringIsArithmeticSym(line.Substring(index_pos, 1)) || (index_pos < line.Length - 1 && StringIsArithmeticSym(line.Substring(index_pos, 2)))))
                {
                    word += line[index_pos++];
                }
                
                if (commentedLine)
                    return "";
            }
            return word;
        }
        /// <summary>
        /// Peeks the next character on the line.
        /// </summary>
        /// <param name="index_pos">The position within the string where to start the reading</param>
        /// <param name="line">The string which is to be read</param>
        /// <param name="peeked">The character peeked from the string</param>
        /// <returns>The line position at which the character was peeked from</returns>
        static int PeekChar(int index_pos, string line, out char peeked)
        {
            //Flag indicating if parsed word is commented
            bool commentedLine = false;//C++ type of comment "//"
            bool commentedSection = false;//Block type comment "/* ... */"

            if (index_pos < 0 || index_pos > line.Length - 1)
            {
                peeked = ' ';
                return -1;
            }

            if (index_pos > -1 && line.Length > 0)
            {
                while (index_pos < line.Length && (Calculator.CharIsWordSeparator(line[index_pos])))
                    index_pos++;

                if (line[index_pos] == '/')
                {
                    if (index_pos + 1 < line.Length && line[index_pos + 1] == '/')
                        commentedLine = true;
                    else if (index_pos + 1 < line.Length && line[index_pos + 1] == '*')
                        commentedSection = true;
                }

                if (commentedSection)
                {
                    if (commentedSection)
                    {
                        //Jump over the start of the comment - "/*"
                        index_pos += 2;

                        while (index_pos < line.Length - 1 && !(line[index_pos] == '*' && line[index_pos + 1] == '/'))
                            index_pos++;

                        //Check if line end was not the case to stop the traversal - if it is not, end of the comment should be found - "*/"
                        if (index_pos < line.Length - 1 && line[index_pos] == '*' && line[index_pos + 1] == '/')
                            index_pos += 2;//Jump over the end of the comment - "*/"

                        commentedSection = false;
                    }
                }

                if (commentedLine)
                {
                    peeked = '\0';
                    return index_pos;
                }
            }
            peeked = line[index_pos];
            return index_pos;
        }
        /// <summary>
        /// Reads a string from the provided line - string defined from quote to quote symbol.
        /// </summary>
        /// <param name="index_pos">The position within the string where to start the reading</param>
        /// <param name="line">The string which is to be read</param>
        /// <returns>The string extratced from the provided line</returns>
        static string ReadString(ref int index_pos, string line)
        {
            string readString = "";
            char peek;
            int peekPos = PeekChar(index_pos, line, out peek);
            if (peek == '\"')
            {
                index_pos = peekPos + 1;

                peekPos = PeekChar(index_pos++, line, out peek);
                while (index_pos < line.Length && peek != '\"')
                {
                    for (; index_pos <= peekPos; index_pos++)
                        readString += " ";
                    readString += peek;
                    peekPos = PeekChar(index_pos++, line, out peek);
                }
                if (peek == '\"')
                    index_pos++;
            }

            return readString;
        }
        /// <summary>
        /// Resolves any structure acces and prepares an infix notated arithmetic expression string
        /// </summary>
        /// <param name="linePos">Position within the line where parsing should start</param>
        /// <param name="cmdLine">String containing expression to be parsed</param>
        /// <param name="scrComponents">All of the possible script components that are currently supported</param>
        /// <returns>Infix notated arithmetic expression</returns>
        static string ParseInfixArithmeticExpression(ref int linePos, string cmdLine, ScrMainModule.ScrComp scrComponents)
        {
            string expression = "";
            string scrWord = ReadWord(ref linePos, cmdLine);

            while (linePos < cmdLine.Length && scrWord != ";")
            {
                GenPayloadStruct pldAccess = ResolveScriptPayloadStruct("RTE", scrWord, scrComponents);
                if (pldAccess == null)
                {
                    string compName = scrWord;
                    scrWord = ReadWord(ref linePos, cmdLine);
                    pldAccess = ResolveScriptPayloadStruct(compName, scrWord, scrComponents);

                    if (pldAccess == null)
                    {
                        //Restore parsing
                        linePos -= scrWord.Length;
                        scrWord = compName;
                    }
                }

                if (pldAccess != null)
                {
                    if (ReadWord(ref linePos, cmdLine) == ".")
                    {
                        scrWord = ReadWord(ref linePos, cmdLine);
                        expression += pldAccess[pldAccess[scrWord]].ToString();
                    }
                    else
                        throw new Exception("Missing structuter accessor.");
                }
                else
                {
                    if (Calculator.StringIsArithmeticOperation(scrWord))
                    {
                        expression += scrWord;
                    }
                    else if (scrWord.Length > 0)
                    {
                        expression += Calculator.ParseUInteger(scrWord).ToString();
                    }
                }

                expression += " ";
                scrWord = ReadWord(ref linePos, cmdLine);
            }

            return expression;
        }

        static public void paramsStructureSettingsParse(GenPayloadStruct aeucSettData, GenPayloadStruct aeucDestData)
        {
            for (int i = 0; i < aeucDestData.structContentsStringRep.Length; i++)
            {
                try
                {
                    aeucDestData[aeucDestData[aeucDestData.structContentsStringRep[i].dispName]] = aeucSettData[aeucSettData[aeucDestData.structContentsStringRep[i].dispName]];
                }
                catch
                {
                    aeucDestData.setStringItem(aeucDestData[aeucDestData.structContentsStringRep[i].dispName], aeucSettData.getParamStringVal(aeucSettData[aeucDestData.structContentsStringRep[i].dispName]));
                }
            }
        }
        #endregion

        /// <summary>
        /// Copies contents from source input struct to the destination input struct
        /// </summary>
        /// <param name="source">Source struct</param>
        /// <param name="destination">Destination struct</param>
        /// <returns>True if operation is successful</returns>
        static public bool CopyStructs(GenPayloadStruct source, GenPayloadStruct destination)
        {
            if (destination.Editable)
            {
                //destination.StructContents = source.StructContents;
                //destination.structContentsStringRep = source.structContentsStringRep;

                destination.AddPayloadItems(source.StructContents, source.structContentsStringRep);
                return true;
            }

            if (source.structContentsStringRep.Length != destination.structContentsStringRep.Length)
                return false;

            for (int i = 0; i < source.structContentsStringRep.Length; i++)
            {
                if ((source.structContentsStringRep[i].dispName != destination.structContentsStringRep[i].dispName) ||
                    (source.structContentsStringRep[i].paramId != destination.structContentsStringRep[i].paramId))
                    return false;
            }

            for (int i = 0; i < source.structContentsStringRep.Length; i++)
            {
                source[source.structContentsStringRep[i].paramId] = destination[destination.structContentsStringRep[i].paramId];
            }

            return true;
        }

        /// <summary>
        /// Searches for the script action in the provided list of actions
        /// </summary>
        /// <param name="scrWord">Name of the script action to search for</param>
        /// <param name="scrActions">List of all the accessible script actions</param>
        /// <returns>Reference to the found script action or null</returns>
        static ScrBasicAction ResolveScriptAction(string scrWord, ScrBasicAction[] scrActions)
        {
            ScrBasicAction resAct = null;
            for (int i = 0; i < scrActions.Length; i++)
            {
                if (scrActions[i].DisplayName == scrWord)
                {
                    resAct = scrActions[i];
                    break;
                }
            }

            return resAct;
        }
        /// <summary>
        /// Fills in objects of the specified type in a parameter list object, that is to be fed to a script action do method.
        /// </summary>
        /// <param name="prmList">Paramater list object that is being resolved</param>
        /// <param name="linePos">Position within the line that the parameter list is expected to be found</param>
        /// <param name="cmdLine">The command line to be parsed and executed</param>
        /// <param name="scrComponents">All of the possible script components that are currently supported</param>
        /// <returns>The parameter list object with appropriate objects inserted</returns>
        static List<object> ResolveActionParamList(List<Type> prmList, ref int linePos, string cmdLine, ScrMainModule.ScrComp scrComponents)
        {
            bool treatAsString = false;
            char peek;
            string scrWord;
            List<object> objList = new List<object>();
            if (prmList != null)
            {
                for (int i = 0; i < prmList.Count; i++)
                {
                    Type argType = prmList[i];

                    if (argType == typeof(ScrRunTimeEnv))
                    {
                        objList.Add(scrComponents.rteCmn);
                        continue;
                    }

                    treatAsString = false;
                    PeekChar(linePos, cmdLine, out peek);
                    scrWord = ReadWord(ref linePos, cmdLine);
                    if (peek == '%')
                    {
                        scrWord = scrWord.Remove(0, 1);//Remove the '%'
                        treatAsString = true;
                    }

                    //If the end of the command line is encountered return whatever has been accumulated so far
                    if (scrWord.Length == 0 || scrWord == ";")
                        return objList;

                    if (argType == typeof(ScrVarArgListType))
                    {
                        argType = prmList[i-- + 1];
                    }
                    
                    if (argType == typeof(GenMSG))
                    {
                        objList.Add(ResolveScriptMessage(scrWord, scrComponents.scrMessages));
                    }
                    else if (argType == typeof(GenPayloadStruct))
                    {
                        GenPayloadStruct pldAccess = ResolveScriptPayloadStruct("RTE", scrWord, scrComponents);
                        if (pldAccess == null)
                        {
                            string compName = scrWord;
                            scrWord = ReadWord(ref linePos, cmdLine);
                            if (scrWord == ".")
                            {
                                scrWord = ReadWord(ref linePos, cmdLine);
                                pldAccess = ResolveScriptPayloadStruct(compName, scrWord, scrComponents);
                            }
                        }

                        objList.Add(pldAccess);
                    }
                    else if (argType == typeof(int))
                    {
                        //If the parameter is of type int, a calculation will be run whatever the expression - even if it's
                        //just dereferencing a structure or a single integer, as the ParseInfixArithmeticExpression would do
                        //all the work and the Calculate will return a correct value even if the expression is single symbol
                        //only.
                        //In this case the first symbol of the expression is already read at the start of this cycle - this
                        //is done in order to stop adding optional parameters if the script command line doesn't have them.
                        //In order to have correct expression parsing, the command line position indexer is returned at the 
                        //start of the "word" that has been already extracted and parsing is done from that point.
                        linePos -= scrWord.Length;
                        objList.Add((int)Calculator.Calculate(ParseInfixArithmeticExpression(ref linePos, cmdLine, scrComponents)));
                    }
                    else if (argType == typeof(string))
                    {
                        objList.Add(scrWord);
                    }
                    else if (argType == typeof(char[]))
                    {
                        GenPayloadStruct pldAccess = ResolveScriptPayloadStruct("RTE", scrWord, scrComponents);
                        if (pldAccess == null)
                        {
                            string compName = scrWord;
                            scrWord = ReadWord(ref linePos, cmdLine);
                            pldAccess = ResolveScriptPayloadStruct(compName, scrWord, scrComponents);

                            if (pldAccess == null)
                            {
                                //Restore parsing
                                linePos -= scrWord.Length;
                                scrWord = compName;
                            }
                        }

                        if (pldAccess != null)
                        {
                            if (ReadWord(ref linePos, cmdLine) == ".")
                            {
                                scrWord = ReadWord(ref linePos, cmdLine);
                                objList.Add(pldAccess.getParamStringVal(pldAccess[scrWord]).ToCharArray());
                            }
                            else
                                throw new Exception("Missing structuter accessor.");
                        }
                        else
                        {
                            linePos -= (scrWord.Length + 1);
                            PeekChar(linePos, cmdLine, out peek);
                            if (peek == '\"')
                            {
                                objList.Add(ReadString(ref linePos, cmdLine).ToCharArray());
                            }
                            else
                                throw new Exception("String value or structure field expected.");
                        }
                    }
                    else if (argType == typeof(object))
                    {
                        GenMSG tmpMsg;
                        GenPayloadStruct pldAccess;
                        string field;
                        string infixCalc;
                        int linePosSave;
                        #region stupid...

                        linePosSave = linePos;
                        if (!treatAsString)
                        {
                            tmpMsg = ResolveScriptMessage(scrWord, scrComponents.scrMessages);
                            if (tmpMsg != null)
                            {
                                objList.Add(tmpMsg);
                                continue;
                            }

                            pldAccess = ResolveScriptPayloadStruct("RTE", scrWord, scrComponents);
                            if (pldAccess == null)
                            {
                                string compName = scrWord;
                                field = ReadWord(ref linePos, cmdLine);
                                if (field == ".")
                                {
                                    field = ReadWord(ref linePos, cmdLine);
                                    pldAccess = ResolveScriptPayloadStruct(compName, field, scrComponents);
                                }

                                if (pldAccess == null)
                                {
                                    linePos = linePosSave;
                                }
                            }
                            if (pldAccess != null)
                            {
                                field = ReadWord(ref linePos, cmdLine);
                                if (field == ".")
                                {
                                    field = ReadWord(ref linePos, cmdLine);
                                    objList.Add(pldAccess[pldAccess[field]]);
                                }
                                else
                                {
                                    linePos -= field.Length;
                                    objList.Add(pldAccess);
                                }
                                continue;
                            }

                            //If the parameter is of type int, a calculation will be run whatever the expression - even if it's
                            //just dereferencing a structure or a single integer, as the ParseInfixArithmeticExpression would do
                            //all the work and the Calculate will return a correct value even if the expression is single symbol
                            //only.
                            //In this case the first symbol of the expression is already read at the start of this cycle - this
                            //is done in order to stop adding optional parameters if the script command line doesn't have them.
                            //In order to have correct expression parsing, the command line position indexer is returned at the 
                            //start of the "word" that has been already extracted and parsing is done from that point.
                            linePos -= scrWord.Length;
                            try
                            {
                                infixCalc = ParseInfixArithmeticExpression(ref linePos, cmdLine, scrComponents);
                            }
                            catch
                            {
                                infixCalc = "";
                                linePos = linePosSave;
                            }
                            if (infixCalc != "")
                            {
                                objList.Add(Calculator.Calculate(infixCalc));
                                continue;
                            }
                        }

                        try
                        {
                            pldAccess = ResolveScriptPayloadStruct("RTE", scrWord, scrComponents);
                            field = "";
                            if (pldAccess == null)
                            {
                                string compName = scrWord;
                                field = ReadWord(ref linePos, cmdLine);
                                pldAccess = ResolveScriptPayloadStruct(compName, field, scrComponents);
                            }

                            if (pldAccess != null)
                            {
                                field = ReadWord(ref linePos, cmdLine);
                                if (field == ".")
                                {
                                    field = ReadWord(ref linePos, cmdLine);
                                    try
                                    {
                                        objList.Add(pldAccess.getParamStringVal(pldAccess[field]).ToCharArray());
                                    }
                                    catch
                                    {
                                        linePos = linePosSave;
                                    }
                                }
                            }
                            else
                            {
                                linePos = linePosSave - scrWord.Length;
                                PeekChar(linePos, cmdLine, out peek);
                                if (peek == '\"')
                                {
                                    objList.Add(ReadString(ref linePos, cmdLine).ToCharArray());
                                }
                                else
                                    throw new Exception("String value or structure field expected.");
                            }
                        }
                        catch
                        {
                            objList.Add(scrWord);
                        }
#endregion
                    }
                    else
                        throw new Exception("Unsupported command input parameter!");
                }
            }

            return objList;
        }
        /// <summary>
        /// Searches for the script message in the provided list of messages
        /// </summary>
        /// <param name="scrWord">Name of the script message to search for</param>
        /// <param name="scrMessages">List of all the accessible script messages</param>
        /// <returns>Reference to the found script message or null</returns>
        static GenMSG ResolveScriptMessage(string scrWord, GenMSG[] scrMessages)
        {
            GenMSG resMsg = null;
            for (int i = 0; i < scrMessages.Length; i++)
            {
                if (scrMessages[i].msgDisplayName == scrWord)
                {
                    resMsg = scrMessages[i];
                    break;
                }
            }

            return resMsg;
        }
        /// <summary>
        /// Searches for the script payload struct in the provided list of payload structs
        /// </summary>
        /// <param name="ComName">Name of the script component the structure is located in</param>
        /// <param name="scrWord">Name of the script payload struct to search for</param>
        /// <param name="scrComponents">Reference to the runtime associated script components</param>
        /// <returns>Reference to the found script payload struct or null</returns>
        static public GenPayloadStruct ResolveScriptPayloadStruct(string ComName, string scrWord, ScrMainModule.ScrComp scrComponents)
        {
            GenPayloadStruct resPld = null;
            int iCom = 0;
            for (iCom = 0; iCom < scrComponents.compHdls.Length; iCom++)
            {
                if (scrComponents.compHdls[iCom].OMXCompName == ComName)
                    break;
            }

            if (iCom == scrComponents.compHdls.Length)
                return null;

            for (int i = 0; i < scrComponents.compHdls[iCom].scrPldStructs.Length; i++)
            {
                if (scrComponents.compHdls[iCom].scrPldStructs[i].dispName == scrWord)
                {
                    resPld = scrComponents.compHdls[iCom].scrPldStructs[i];
                    break;
                }
            }

            return resPld;
        }
    }
}
